<template>
  <input
    v-model="inputValue"
    :style="customStyle"
    :type="type"
    :password="password"
    :placeholder="placeholder"
    :placeholder-style="placeholderStyle"
    :placeholder-class="placeholderClass"
    :disabled="disabled"
    :focus="focus"
    :cursor-spacing="cursorSpacing"
    class="v-input"
    @input="inputHandle"
    @focus="(event: FocusEvent) => $emit('focus', event)"
    @blur="(event: FocusEvent) => $emit('blur', event)"
    @confirm="() => $emit('confirm')"
  >
</template>

<script setup lang="ts">
import type { CSSProperties } from 'vue';

/** https://uniapp.dcloud.net.cn/component/input.html#input */
const props = withDefaults(
  defineProps<{
    modelValue?: string;
    replace?: RegExp;
    customStyle?: CSSProperties;
    type?:
      | 'text'
      | 'number'
      | 'idcard'
      | 'digit'
      | 'tel'
      | 'safe-password'
      | 'nickname';
    password?: boolean;
    placeholder?: string;
    placeholderStyle?: string;
    placeholderClass?: string;
    disabled?: boolean;
    maxlength?: number | string;
    focus?: boolean;
    confirmType?: string;
    cursorSpacing?: number;
  }>(),
  {
    modelValue: '',
    replace: undefined,
    customStyle: undefined,
    type: undefined,
    placeholder: '',
    placeholderStyle: undefined,
    placeholderClass: 'placeholder',
    disabled: false,
    maxlength: -1,
    focus: false,
    confirmType: undefined,
    cursorSpacing: 12
  }
);

interface Emits {
  (event: 'update:model-value', val: string): void;
  (event: 'input', val: string): void;
  (event: 'focus', val: FocusEvent): void;
  (event: 'blur', val: FocusEvent): void;
  (event: 'confirm'): void;
  (event: 'paste', val: Event): void;
}
const emits = defineEmits<Emits>();

const inputValue = ref('');

const modelValue = toRef(props, 'modelValue');
const replace = toRef(props, 'replace');
const maxlength = toRef(props, 'maxlength');
const type = toRef(props, 'type');

watch(
  modelValue,
  (val) => {
    if (val !== inputValue.value) {
      inputValue.value = val;
    }
  },
  { immediate: true }
);

const length = computed(() => {
  switch (typeof maxlength.value) {
    case 'string': {
      const length = parseInt(maxlength.value);
      return isNaN(length) ? undefined : length;
    }
    case 'number':
      return maxlength.value >= 0 ? maxlength.value : undefined;
    default:
      return undefined;
  }
});
const inputHandle = async (event: Event) => {
  const value = (event as InputEvent).detail.value;
  inputValue.value = value;
  let formated = replace.value ? value.replace(replace.value, '') : value;
  if (length.value !== undefined) formated = formated.slice(0, length.value);
  await new Promise((resolve) => nextTick(() => resolve(true)));
  inputValue.value = formated;
  emits('update:model-value', formated);
  await new Promise((resolve) => nextTick(() => resolve(true)));
  emits('input', formated);
};
</script>

<style lang="css" scoped>
.v-input {
  font-size: 28rpx;
  padding: 12rpx 0;
  margin: -12rpx 0;
  background-color: transparent;
  width: 100%;
  font-size: inherit;
}
</style>
